package br.org.acessobrasil.portal.facade;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import org.apache.log4j.Logger;
import org.springframework.transaction.annotation.Transactional;

import br.org.acessobrasil.facade.FacadeException;
import br.org.acessobrasil.facade.GenericFacade;
import br.org.acessobrasil.portal.Gerenciador;
import br.org.acessobrasil.portal.action.itemConteudo.ItemConteudoInterface;
import br.org.acessobrasil.portal.controle.AsesCliente;
import br.org.acessobrasil.portal.controle.SecurityManager;
import br.org.acessobrasil.portal.modelo.Arquivo;
import br.org.acessobrasil.portal.modelo.Conteudo;
import br.org.acessobrasil.portal.modelo.ConteudoFormatado;
import br.org.acessobrasil.portal.modelo.InformacaoTipoConteudo;
import br.org.acessobrasil.portal.modelo.ItemConteudo;
import br.org.acessobrasil.portal.modelo.Pagina;
import br.org.acessobrasil.portal.modelo.TipoConteudo;
import br.org.acessobrasil.portal.modelo.Usuario;
import br.org.acessobrasil.portal.persistencia.ArquivoDaoSpring;
import br.org.acessobrasil.portal.persistencia.ConteudoDaoSpring;
import br.org.acessobrasil.portal.persistencia.InformacaoTipoConteudoDao;
import br.org.acessobrasil.portal.persistencia.ItemConteudoDaoSpring;
import br.org.acessobrasil.portal.persistencia.LogDao;
import br.org.acessobrasil.processoacessibilidade.bo.Retificador;

public class ItemConteudoFacade extends GenericFacade<Usuario, ItemConteudo> {
	private static final Logger logger = Logger.getLogger(ItemConteudoFacade.class);
	private ItemConteudoDaoSpring itemConteudoDao;
	private ConteudoDaoSpring conteudoDao;
	public ItemConteudoDaoSpring getItemConteudoDao() {
		return itemConteudoDao;
	}
	
	public void setItemConteudoDao(ItemConteudoDaoSpring itemConteudoDao) {
		this.itemConteudoDao = itemConteudoDao;
	}
	
	private LogDao logDao; 
	public LogDao getLogDao() {
		return logDao;
	}
	
	public void setLogDao(LogDao logDao) {
		this.logDao = logDao;
	}


	public ItemConteudoFacade(LogDao logDao) {
		this.logDao = logDao;
	}
	
	public ItemConteudoFacade() {
	}
	
	/**
	 * Valida a acessibilidade e cria
	 */
	public void criar(Usuario usuario, ItemConteudo itemConteudo) throws FacadeException {
		//paranoid mode, deve se utilizar o dao
		criar(usuario, itemConteudo, false,false);
	}
	
	/**
	 * Valida a acessibilidade e cria
	 */
	public void criar(Usuario usuario, ItemConteudo itemConteudo, EntityManager em) throws FacadeException {
		//paranoid mode, deve se utilizar o dao
		criar(usuario, itemConteudo, false, false);
	}
	
	/**
	 * Valida a acessibilidade e cria
	 */
	public void criar(Usuario usuario, ItemConteudo itemConteudo,boolean salvarPublicado,boolean acessibilizarAutomaticamente) throws FacadeException {
		try {
			if(!SecurityManager.podeAlterarItemConteudo(usuario, itemConteudo)){
				usuario.addActionError("Voc&ecirc; n&atilde;o possui autoriza&ccedil;&atilde;o para inserir este conte�do.");
				logDao.addLog(usuario,"Tentativa de inserir item no conteudo cod = " + itemConteudo.getNuConteudo());	
				return;
			}
			if(acessibilizarAutomaticamente){
				for(ConteudoFormatado conteudoFormatado:itemConteudo.getListConteudoFormatado()){
					if(conteudoFormatado.getInformacaoTipoConteudo().getNuFormato().equals(Gerenciador.TIPO_RTF)){
						Retificador retificador = new Retificador();
						retificador.setColocarDocType(false);
						String codHtml=retificador.consertarErroAcessibilidade(conteudoFormatado.getDeConteudo());
						codHtml=retificador.consertarErroHtml(codHtml);
						conteudoFormatado.setDeConteudo(codHtml);
					}
				}
			}
			boolean ok = avaliarAcessibilidade(itemConteudo);
			if(ok){
				if(salvarPublicado){
					itemConteudo.setStSituacao('p');
				}else{
					itemConteudo.setStSituacao('r');
				}
			}else{
				itemConteudo.setStSituacao('a');
			}
			itemConteudo.setNuItemConteudo(null);
			itemConteudoDao.create(itemConteudo);
			itemConteudoDao.getEntityManager().flush();
			Conteudo conteudo = getEntityManager().find(Conteudo.class, itemConteudo.getNuConteudo());
			conteudo.getPagina().setDataControleDeCache(new Date());
			String msg="Item de Conte&uacute;do adicionado. ['"+itemConteudo.getNoTitulo()+"',id = "+itemConteudo.getNuItemConteudo()+"].";
			logDao.addLog(usuario,msg);
			usuario.addActionMessage("Adicionado com sucesso!");
		} catch(Exception e) {
			usuario.addActionError("Erro: " + e.getMessage());
			logger.error("Erro: " + e.getMessage(),e);
		}
		Gerenciador.limparCache();
	}
	
	@Override
	public void excluir(Usuario usuario, ItemConteudo itemConteudo) throws FacadeException {
		if(!SecurityManager.podeAlterarItemConteudo(usuario, itemConteudo)){
			usuario.addActionError("Voc&ecirc; n&atilde;o possui autoriza&ccedil;&atilde;o para apagar este conte&uacute;do.");
			return;
		}
		/*
		 * Verificar se ele possui filho e pai, caso tenha juntar o pai com o filho
		 */
		try{
			if(itemConteudo.getNuItemConteudoPai()!=null && itemConteudo.getNuItemConteudoFilho()!=null){
				ItemConteudo pai = itemConteudoDao.select(itemConteudo.getNuItemConteudoPai());
				ItemConteudo filho = itemConteudoDao.select(itemConteudo.getNuItemConteudoFilho());
				if(pai!=null && filho!=null){
					pai.setNuItemConteudoFilho(filho.getNuItemConteudo());
					filho.setNuItemConteudoPai(pai.getNuItemConteudo());
					itemConteudoDao.update(pai);
					itemConteudoDao.update(filho);
					logger.debug("Ligou o pai " + pai.getNuItemConteudo() + " com " + filho.getNuItemConteudo());
				}
			}
			itemConteudoDao.apagar(itemConteudo);
			itemConteudo.getConteudo().getPagina().setDataControleDeCache(new Date());
			
			String msg="Item de Conte&uacute;do apagado. ['"+itemConteudo.getNoTitulo()+"',id = "+itemConteudo.getNuItemConteudo()+"].";
			logDao.addLog(usuario,msg);
			usuario.addActionMessage("Item de conte&uacute;do apagado com sucesso.");
		}catch(Exception e){
			usuario.addActionError("Erro: Ocorreu um erro ao apagar o item.");
			logger.error("Erro ao religar a lista",e);
		}
	}
	
	/**
	 * Retorna todas as datas, todos os anos todos os meses
	 * 
	 * @param nuConteudo
	 * @return List&lt;Date>
	 */
	@Transactional(readOnly=true)
	public List<Date> verTodosArquivos(Long nuConteudo) {
		List<Date> retorno = new ArrayList<Date>();
		Query q = getEntityManager().createQuery("Select o From " + ItemConteudo.class.getSimpleName() + " o where o.nu_conteudo=:nuConteudo and o.st_situacao='p' order by o.dt_para_publicacao asc");
		q.setMaxResults(1);
		q.setParameter("nuConteudo", nuConteudo);
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM");
		// na verdade so vem um para resgatar a data inicial
		List<ItemConteudo> itens = q.getResultList();
		long dataAtual = new Date().getTime();
		if (itens.size() > 0) {
			Date temp = itens.get(0).getDtParaPublicacao();
			String formatado = simpleDateFormat.format(temp);
			String[] anoMes = formatado.split("-");
			int ano, mes;
			ano = Integer.parseInt(anoMes[0]);
			mes = Integer.parseInt(anoMes[1]);
			logger.debug("ano " + ano + " mes " + mes + " inicio");
			while (temp.getTime() < dataAtual) {
				try {
					Date nextDate = somarUmMes(temp);
					long tot = contarItensConteudo(nuConteudo, temp, nextDate);
					if(tot>0){
						retorno.add(temp);
					}
					logger.debug(temp.toString() + " incluido");
					temp = nextDate;
				} catch (Exception e) {
					e.printStackTrace();
					break;
				}
			}
		} else {
			logger.debug("Sem arquivos");
		}
		return retorno;
	}

	public Conteudo buscarConteudo(Long nuConteudo) {
		return getEntityManager().find(Conteudo.class, nuConteudo);
	}
	
	/**
	 * Gera uma pagina de arquivo parecido com um blog.
	 * Coloca a lista dentro do setDeCabecalho
	 * @param nuConteudo id do conteudo
	 * @param deConteudo descricao do conteudoFormatado
	 * @return Pagina
	 */
	@Transactional(readOnly=true)
	public Pagina gerarPaginaArquivoItemConteudo(Long nuConteudo, String deConteudo) {
		Conteudo conteudo = buscarConteudo(nuConteudo);

		Pagina pagina = new Pagina();
		// inicializar a lista
		int total = conteudo.getSitio().getMenuPrincipal().getListItemMenu().size();
		logger.debug("itens de menu = " + total);

		pagina.setSitio(conteudo.getSitio());
		pagina.setNuItemMenuSecao(conteudo.getPagina().getNuItemMenuSecao());
		pagina.setNoTitulo("Arquivos");
		pagina.setPadraoApresentacao(conteudo.getPagina().getPadraoApresentacao());
		List<Conteudo> listConteudo = new ArrayList<Conteudo>();
		// criar um tipo de conteudo
		TipoConteudo tipoConteudo = new TipoConteudo();
		tipoConteudo.setNoTipoConteudo(Gerenciador.TIPO_CONTEUDO_ARQUIVO_DE_ITEM);
		// criar um conteudo
		Conteudo conteudoArquivo = new Conteudo();
		conteudoArquivo.setNoConteudo(conteudo.getNoConteudo());
		conteudoArquivo.setTipoConteudo(tipoConteudo);

		ItemConteudo itemConteudo = new ItemConteudo();
		itemConteudo.setNoTitulo("Arquivos");
		InformacaoTipoConteudo informacaoTipoConteudo = new InformacaoTipoConteudo();
		informacaoTipoConteudo.setCoAtivo(true);
		informacaoTipoConteudo.setNuFormato(Gerenciador.TIPO_RTF);
		informacaoTipoConteudo.setNoTag("arquivo");
		conteudoArquivo.setDeCabecalho(deConteudo);
		listConteudo.add(conteudoArquivo);
		pagina.setListConteudo(listConteudo);
		return pagina;
	}

	private Date somarUmMes(Date data) throws ParseException{
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM");
		String formatado = simpleDateFormat.format(data);
		String[] anoMes = formatado.split("-");
		int intAno, intMes;
		intAno = Integer.parseInt(anoMes[0]);
		intMes = Integer.parseInt(anoMes[1]);
		// verifica se incrementa o ano ou o mes
		if (intMes < 12) {
			intMes++;
			// Formata o numero
			if (intMes < 10) {
				return simpleDateFormat.parse(intAno + "-" + intMes);
			} else {
				return simpleDateFormat.parse(intAno + "-0" + intMes);
			}
		} else {
			intAno++;
			return simpleDateFormat.parse(intAno + "-01");
		}
	}
	
	@Transactional(readOnly=true)
	public long contarItensConteudo(Long nuConteudo, Date ini, Date fim) throws Exception {
		Query q = getEntityManager().createQuery("Select count(o) From " + ItemConteudo.class.getSimpleName() + " o where o.nu_conteudo=:nuConteudo and :ini<=o.dt_para_publicacao and o.dt_para_publicacao<:fim order by o.dt_para_publicacao");
		q.setParameter("nuConteudo",nuConteudo);
		q.setParameter("ini", ini);
		q.setParameter("fim",fim);
		return (Long)q.getSingleResult();
	}
	
	@Transactional(readOnly=true)
	public List<ItemConteudo> buscarItensConteudo(Long nuConteudo, String ano, String mes) throws Exception {
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM");
		Date ini = simpleDateFormat.parse(ano+"-"+mes);
		Date fim = somarUmMes(ini);
		
		Query q = getEntityManager().createQuery("Select o From " + ItemConteudo.class.getSimpleName() + " o where o.nu_conteudo=:nuConteudo and :ini<=o.dt_para_publicacao and o.dt_para_publicacao<:fim order by o.dt_para_publicacao");
		q.setParameter("nuConteudo",nuConteudo);
		q.setParameter("ini", ini);
		q.setParameter("fim",fim);
		List<ItemConteudo> itens = q.getResultList();
		//Inicializar
		for(ItemConteudo item:itens)
			item.getConteudo().getPagina().getNuPagina();
		return itens;
	}
	
	public ItemConteudo despublicar(Long nuItemConteudo,Usuario usuario) throws Exception {
		logger.debug("Despublicando item Conteudo = "+nuItemConteudo);
		ItemConteudo itemConteudo = null;
		try {
			itemConteudo = buscar(usuario , nuItemConteudo);

			if(itemConteudo.getStSituacao()!='p'){// verificar se esta publicado
				usuario.addActionMessage(getString("erro.item_nao_publicado")+nuItemConteudo);
				return itemConteudo;
			}
			if(!SecurityManager.podeAlterarItemConteudo(usuario, itemConteudo)){
				usuario.addActionError(getString("erro.autorizar.item"));
				return itemConteudo;
			}
			boolean ok = avaliarAcessibilidade(itemConteudo);
			if(ok){
				itemConteudo.setStSituacao('r');
				itemConteudo.setStSituacaoAnterior('r');
				usuario.addActionMessage(getString("sucesso.despublicar")+nuItemConteudo);
				logDao.addLog(usuario, "despublicou o item de conteudo ["+itemConteudo.getNoTitulo()+" id = "+itemConteudo.getNuItemConteudo()+"]");
			}else{
				itemConteudo.setStSituacao('a');
				usuario.addActionError(getString("erro.acessibilidade.generic"));
				logDao.addLog(usuario, "Sistema encontrou erros de acessibilidade ao despublicar item ["+itemConteudo.getNoTitulo()+" id = "+itemConteudo.getNuItemConteudo()+"]");
			}
			itemConteudoDao.update(itemConteudo);
			//setItemConteudo(itemConteudo);
			logger.debug("Item Conteudo = "+nuItemConteudo+" despublicado.");
		}catch(Exception e){
			usuario.addActionError(getString("erro.despublicar.item")+e.getMessage());
			logger.error("erro ao despublicar item", e);
		}				
		return itemConteudo;
	}

	public ItemConteudo publicar(Long nuItemConteudo,Usuario usuario) {
		logger.debug("Publicando item Conteudo = "+nuItemConteudo);
		ItemConteudo itemConteudo = null;
		try {
			itemConteudo = buscar(usuario, nuItemConteudo);
			//verificar se ja esta publicado
			if(itemConteudo.getStSituacao()=='p'){
				usuario.addActionMessage(getString("aviso.item_ja_publicado")+nuItemConteudo);
				return itemConteudo;
			}
			if(itemConteudo.getStSituacao()=='b'){
				//TODO restauramos automaticamente?
				usuario.addActionError(getString("erro.publicando_backup")+nuItemConteudo);
				return itemConteudo;
			}
			if(!SecurityManager.podeAlterarItemConteudo(usuario, itemConteudo)){
				usuario.addActionError(getString("erro.autorizar.item"));
				return itemConteudo;
			}
			boolean ok = avaliarAcessibilidade(itemConteudo);
			if(ok){
				//Marcar todos os pais como backup
				if(itemConteudo.getNuItemConteudoPai()!=null && !itemConteudo.getNuItemConteudoPai().equals(0L)){
					ItemConteudo itemConteudoPai = buscar(usuario , itemConteudo.getNuItemConteudoPai());
					while(itemConteudoPai!=null){
						//marcar como b de backup
						itemConteudoPai.setStSituacaoAnterior(itemConteudoPai.getStSituacao());
						itemConteudoPai.setStSituacao('b');
						atualizar(itemConteudoPai);
						if(itemConteudoPai.getNuItemConteudoPai()==null || itemConteudoPai.getNuItemConteudoPai().equals(0L)){
							break;
						}
						itemConteudoPai = buscar(usuario , itemConteudoPai.getNuItemConteudoPai());
					}
				}
				itemConteudo.setStSituacao('p');
				logDao.addLog(usuario, "Publicou o item de conteudo ["+itemConteudo.getNoTitulo()+" id = "+itemConteudo.getNuItemConteudo()+"]");
				usuario.addActionMessage(getString("sucesso.publicar")+nuItemConteudo);
			}else{
				itemConteudo.setStSituacao('a');
				logDao.addLog(usuario, "Erro de acessibilidad encontrado ao publicar ["+itemConteudo.getNoTitulo()+" id = "+itemConteudo.getNuItemConteudo()+"]");
				usuario.addActionError(getString("erro.publicar.acessibilidade")+nuItemConteudo);
			}
			logger.debug("Item Conteudo = "+nuItemConteudo+" publicado.");			
		} catch (Exception e) {
			usuario.addActionError(getString("erro.publicar.item")+e.getMessage());
			logger.error("erro ao publicarItem", e);
		}
		return itemConteudo;
	}
	
	/**
	 * Verifica a permissao, avalia a acessibilidade e atualiza a dada da pagina para controle de cache
	 */
	@Override
	public ItemConteudo atualizar(Usuario usuario, ItemConteudo itemConteudo) throws FacadeException {
		if(!SecurityManager.podeAlterarItemConteudo(usuario, itemConteudo)){
			usuario.addActionError(getString("erro.autorizar.item"));
			return null;
		}
		
		atualizar(itemConteudo);
		
		itemConteudo.getConteudo().getPagina().setDataControleDeCache(new Date());
		
		usuario.addActionMessage("Atualizado com sucesso!");
		String msg="Item de Conte&uacute;do Editado com sucesso. ['"+itemConteudo.getNoTitulo()+"',id = "+itemConteudo.getNuItemConteudo()+"].";
		logDao.addLog(usuario,msg);
		return itemConteudo;
	}
	
	
	private void atualizar(ItemConteudo itemConteudo) throws FacadeException{
		boolean ok = avaliarAcessibilidade(itemConteudo); 
		if(!ok){
			itemConteudo.setStSituacao('a');
		}
		if(itemConteudo.getStSituacao()=='a' && ok){
			//se nao possui erros e a situacao estava errada, volta para rascunho
			itemConteudo.setStSituacao('r');
		}
		try {
			itemConteudoDao.update(itemConteudo);
		} catch (Exception e) {
			throw new FacadeException(e);
		}
	}
	
	/**
	 * Popula o relatorio de acessibilidade no conteudoFormatado
	 * @param itemConteudo
	 * @return retorna true caso n�o encontre erros
	 */
	public static boolean avaliarAcessibilidade(ItemConteudo itemConteudo) {
		logger.debug("avaliarAcessibilidade iniciado...");
		boolean retorno=true;
		if(itemConteudo.getListConteudoFormatado()==null){
			return true;
		}
		boolean avaliado = false;
		//AsesCliente.setDtdBasePath("http://"+request.getLocalName()+request.getContextPath()+"/dtd");
		for(ConteudoFormatado conteudoFormatado:itemConteudo.getListConteudoFormatado()){
			AsesCliente avaliador = new AsesCliente();
			avaliador.setCorrecaoLinha(-1);
			avaliador.tratar(conteudoFormatado);
			if(conteudoFormatado.getDeConteudo()==null || conteudoFormatado.getDeConteudo().equals("")){
				logger.warn("Campo vazio " +conteudoFormatado.getNuInformacaoTipoConteudo());
			}
			avaliador.avalia(ItemConteudoInterface.strTemplateParaAvaliacao.replace("{conteudo}",conteudoFormatado.getDeConteudo()));
			avaliado=true;
			if(avaliador.isErrado()){
				retorno=false;
				conteudoFormatado.setRelatorioAcessibilidade(avaliador.getRelatorio());
			}
			//System.out.println("conteudoFormatado.getDeConteudo()="+conteudoFormatado.getDeConteudo());
		}
		if(!avaliado){
			logger.warn("Nenhum campo foi avaliado");
		}
		if(!retorno){
			logger.debug("Erros encontrado, alterando estado");
			itemConteudo.setStSituacao('a');
		}
		logger.debug("avaliarAcessibilidade terminado.");
		return retorno;
	}

	@SuppressWarnings("unchecked")
	public void reodenar(Long nu_conteudo){
		try{
			getEntityManager().flush();
		
			Query q = getEntityManager().createQuery("Select item From ItemConteudo item where nu_conteudo = ? order by nu_ordem, nu_item_conteudo");
			q.setParameter(1, nu_conteudo);
			List<ItemConteudo> listaItens = q.getResultList();
			for(int i = 0; i < listaItens.size(); i++){
				listaItens.get(i).setNuOrdem(i + 1);
			}
		}catch (Exception e) {
			logger.error("erro ao reodernar " + e);
		}	
	}	
	@SuppressWarnings("unchecked")
	private List<ItemConteudo> listarItensDeConteudo(Usuario ator,Long nuConteudo) throws FacadeException  {
		Query q = getEntityManager().createQuery("Select o from ItemConteudo o where o.nu_conteudo=? order by nu_ordem, nu_item_conteudo");
		q.setParameter(1,nuConteudo);
		List<ItemConteudo> listarItensDeConteudo = q.getResultList();
		for(int i=0;i<listarItensDeConteudo.size();i++){
			listarItensDeConteudo.get(i).setNuOrdem(i);
		}
		return listarItensDeConteudo;
	}	
	public void aumentarOrdemItem(Usuario ator,	ItemConteudo itemConteudo) throws Exception{
		boolean alterado = false;
		itemConteudo = getEntityManager().find(ItemConteudo.class, itemConteudo.getNuItemConteudo());
		List<ItemConteudo> list = listarItensDeConteudo(ator, itemConteudo.getNuConteudo());
		for(int i = 0 ; i < list.size(); i++){
			ItemConteudo item = list.get(i);
			if(item.getNuItemConteudo().equals(itemConteudo.getNuItemConteudo())){			
				if (i > 0) {
					ItemConteudo itemAcima = list.get(i-1);
					itemConteudo.setNuOrdem(itemAcima.getNuOrdem());
					itemAcima.setNuOrdem(itemAcima.getNuOrdem()+1);
					alterado = true;
				}else{
					throw new Exception("O item j&aacute; &eacute; o  	&uacute;ltimo da lista.");
				} 
				break;
			}
		}
		if(!alterado){
			throw new  Exception("O item com id" + itemConteudo.getNuConteudo() + "nao alterado");
		}
		getEntityManager().flush();
		logDao.addLog(ator, "Alterou ordem para cima do item de menu[id" + itemConteudo.getNuItemConteudo()+ "titulo" + itemConteudo.getNoTitulo()+ "]");
	}
	
	public void diminuirOrdemItem(Usuario ator,	ItemConteudo itemConteudo) throws Exception{
		boolean alterado = false;
		if(itemConteudo==null) throw new NullPointerException("itemConteudo == null");
		itemConteudo = getEntityManager().find(ItemConteudo.class, itemConteudo.getNuItemConteudo());
		List<ItemConteudo> list = listarItensDeConteudo(ator, itemConteudo.getNuConteudo());
		for(int i = 0 ; i < list.size(); i++){
			ItemConteudo item = list.get(i);
			if(item.getNuItemConteudo().equals(itemConteudo.getNuItemConteudo())){
				if((i+1) < list.size()){
					ItemConteudo itemAbaixo = list.get(i+1);
					itemConteudo.setNuOrdem(itemAbaixo.getNuOrdem());
					itemAbaixo.setNuOrdem(itemAbaixo.getNuOrdem()-1);
					alterado = true;
				}else{ 
					throw new Exception("O item j&aacute; &eacute; o  	&uacute;ltimo da lista.");			
				}
				break;
			}
		}
		if(!alterado){
			throw new  Exception("O item com id" + itemConteudo.getNuConteudo() + "nao alterado");
		}
		getEntityManager().flush();
		logDao.addLog(ator, "Alterou ordem para cima do item de menu[id" + itemConteudo.getNuItemConteudo() + "titulo" + itemConteudo.getNoTitulo() + "]");
	}

	public int findAndReplace(Long nuItemConteudo, Usuario usuarioLogado, String procurar, String substituir) {
		int retorno = 0;
		ItemConteudo itemConteudo = getEntityManager().find(ItemConteudo.class, nuItemConteudo);
		Pattern pat = Pattern.compile(procurar,Pattern.DOTALL);
		for(ConteudoFormatado conteudoFormatado:itemConteudo.getListConteudoFormatado()){
			Matcher mat = pat.matcher(conteudoFormatado.getDeConteudo());
			if(mat.find()){
				String conteudo = mat.replaceAll(substituir);
				logger.debug("alterado de :"+conteudoFormatado.getDeConteudo() + " para " + conteudo);
				conteudoFormatado.setDeConteudo(conteudo);
				retorno ++;
			}
		}
		if(retorno!=0){
			boolean ok = avaliarAcessibilidade(itemConteudo); 
			if(!ok){
				itemConteudo.setStSituacao('a');
			}
			if(itemConteudo.getStSituacao()=='a' && ok){
				//se nao possui erros e a situacao estava errada, volta para rascunho
				itemConteudo.setStSituacao('r');
			}
		}
		return retorno;
	}

	/**
	 * Delega para arquivoDao
	 * @param nuArquivo id do arquivo
	 * @return Arquivo
	 * @throws Exception
	 */
	public Arquivo buscarArquivo(Long nuArquivo) throws Exception{
		return getEntityManager().find(Arquivo.class, nuArquivo);
	}
	
	/**
	 * Cria um item de conteudo
	 * @param usuario usuario que pratica esta acao
	 * @param itemConteudo conteudo a ser salvo
	 * @param itemConteudoPai conteudo pai do que esta sendo criado
	 * @throws Exception
	 */
	public void criar(Usuario usuario, ItemConteudo itemConteudo, ItemConteudo itemConteudoPai) throws Exception {
		if(!SecurityManager.podeAlterarItemConteudo(usuario, itemConteudo)){
			usuario.addActionError("Voc&ecirc; n&atilde;o possui autoriza&ccedil;&atilde;o para inserir este conte&uacute;do.");
			return;
		}
		if(itemConteudoPai!=null){
			itemConteudo.setNuItemConteudoPai(itemConteudoPai.getNuItemConteudo());
			itemConteudo.setNuVersao(itemConteudoPai.getNuVersao()+1L);
		}else{
			itemConteudo.setNuVersao(1L);
		}
		itemConteudo.setDtCriacao(new java.util.Date());
		itemConteudo.setDtAlteracao(new java.util.Date());
		itemConteudo.setNuUsuario(usuario.getNuUsuario());
		itemConteudo.setAlteradoNuUsuario(usuario.getNuUsuario());
		itemConteudo.setStSituacao('r');
		itemConteudo.setNuItemConteudo(null);
		itemConteudoDao.create(itemConteudo);
		//atualizar o numero do item atual
		//nu_item_conteudo = itemConteudo.getNuItemConteudo();
		
		//depois de criar
		if(itemConteudoPai!=null){
			itemConteudoPai.setNuItemConteudoFilho(itemConteudo.getNuItemConteudo());
			itemConteudoDao.update(itemConteudoPai);
			try {
				String msg="Item de Conte&uacute;do foi criada uma nova vers&atilde;o. ['"+itemConteudo.getNoTitulo()+"',id = "+itemConteudo.getNuItemConteudo()+"].";
				logDao.addLog(usuario,msg);	
			} catch(Exception e) {}
			usuario.addActionMessage("Criada uma nova vers&atilde;o com sucesso.");
		}else{
			try {
				String msg="Item de Conte&uacute;do adicionado. ['"+itemConteudo.getNoTitulo()+"',id = "+itemConteudo.getNuItemConteudo()+"].";
				logDao.addLog(usuario,msg);	
			} catch(Exception e) {}
			usuario.addActionMessage("Adicionado com sucesso!");
		}
	}
	
	public InformacaoTipoConteudo buscarInformacaoTipoConteudo(Long nuInformacaoTipoConteudo) throws Exception {
		return InformacaoTipoConteudoDao.getInstance().select(nuInformacaoTipoConteudo);
	}
	
	/**
	 * Delegate para ConteudoDaoSpring.listarItemConteudo();
	 * @param conteudo
	 * @param ini
	 * @param max
	 * @param b
	 * @return
	 */
	public List<ItemConteudo> listarItemConteudo(Conteudo conteudo, int ini, int max, boolean b) {
		return conteudoDao.listarItemConteudo(conteudo, ini, max, b);
	}
	
	/**
	 * Utilizado em EditarItemConteudoAction
	 * @param usuario
	 * @param itemConteudoOriginal
	 * @param itemConteudo
	 * @throws Exception
	 */
	public void salvarVersao(Usuario usuario, ItemConteudo itemConteudoOriginal, ItemConteudo itemConteudo) throws Exception {
		long ultimaVersao = itemConteudoOriginal.getNuVersao();
		long ultimoIdFilho = itemConteudoOriginal.getNuItemConteudo();
		ItemConteudo itemConteudoFilho = null;
		if(itemConteudoOriginal.getNuItemConteudoFilho()!=null && !itemConteudoOriginal.getNuItemConteudoFilho().equals(0L)){
			itemConteudoFilho = itemConteudoDao.select(itemConteudoOriginal.getNuItemConteudoFilho());
			while(itemConteudoFilho!=null && itemConteudoFilho.getNuItemConteudoFilho()!=null && !itemConteudoFilho.getNuItemConteudoFilho().equals(0L)){
				//marcar como b de backup todos que nao forem backup
				if(itemConteudoFilho.getStSituacao()!='b'){
					itemConteudoFilho.setStSituacaoAnterior(itemConteudoFilho.getStSituacao());
					itemConteudoFilho.setStSituacao('b');
					itemConteudoDao.update(itemConteudoFilho);
				}
				itemConteudoFilho = itemConteudoDao.select(itemConteudoFilho.getNuItemConteudoFilho());
			}
			if(itemConteudoFilho!=null){
				//marcar como b de backup todos que nao forem backup
				if(itemConteudoFilho.getStSituacao()!='b'){
					itemConteudoFilho.setStSituacaoAnterior(itemConteudoFilho.getStSituacao());
					itemConteudoFilho.setStSituacao('b');
					itemConteudoDao.update(itemConteudoFilho);
				}
				ultimaVersao = itemConteudoFilho.getNuVersao();
				ultimoIdFilho = itemConteudoFilho.getNuItemConteudo();
			}
		}
		
		itemConteudo.setNuItemConteudoPai(ultimoIdFilho);
		itemConteudo.setNuVersao(ultimaVersao+1L);
		
		//mantem a data
		itemConteudo.setDtCriacao(itemConteudoOriginal.getDtCriacao());
		itemConteudo.setDtAlteracao(new java.util.Date());
		itemConteudo.setNuUsuario(usuario.getNuUsuario());
		itemConteudo.setAlteradoNuUsuario(usuario.getNuUsuario());
		boolean ok = avaliarAcessibilidade(itemConteudo);
		if(ok){
			itemConteudo.setStSituacao('r');
		}else{
			itemConteudo.setStSituacao('a');
		}
		
		itemConteudo.setNuItemConteudo(null);
		itemConteudoDao.create(itemConteudo);
		
		//depois de criar
		if(itemConteudoFilho == null ){
			//sem filho entao associa o filho ao conteudo original
			itemConteudoOriginal.setNuItemConteudoFilho(itemConteudo.getNuItemConteudo());
			itemConteudoDao.update(itemConteudoOriginal);
		}else{
			//o original ja possuia filho, entao o novo sera filho do ultimo filho do original
			itemConteudoFilho.setNuItemConteudoFilho(itemConteudo.getNuItemConteudo());
			itemConteudoDao.update(itemConteudoFilho);
		}
		try {
			String msg="Item de Conte&uacute;do foi criada uma nova vers&atilde;o. ['"+itemConteudo.getNoTitulo()+"',id = "+itemConteudo.getNuItemConteudo()+"].";
			logDao.addLog(usuario,msg);	
		} catch(Exception e) {
			logger.error("Erro ao editar item",e);
		}
		usuario.addActionMessage("Criada uma nova vers&atilde;o com sucesso.");		
	}
	
	public ItemConteudo homologar(Usuario usuario, Long nuItemConteudo) {
		ItemConteudo itemConteudo = null;
		try {
			itemConteudo = itemConteudoDao.select(nuItemConteudo);
			if(!SecurityManager.podeAlterarItemConteudo(usuario, itemConteudo)){
				usuario.addActionError("Voc&ecirc; n&atilde;o possui autoriza&ccedil;&atilde;o para editar este conte&uacute;do.");
				return itemConteudo;
			}
			if(itemConteudo.getStSituacao()=='r'){
				itemConteudo.setStSituacao('h');
				itemConteudoDao.update(itemConteudo);
				logDao.addLog(usuario, "Solicitou homologa&ccedil;&atilde;o do item ["+itemConteudo.getNoTitulo()+" id = "+itemConteudo.getNuItemConteudo()+"]");
				usuario.addActionMessage("Item colocado para homologa&ccedil;&atilde;o");
			}else{
				usuario.addActionError("Somente itens em Rascunho podem ir para homologa&ccedil;&atilde;o.");
			}
		} catch (Exception e) {
			usuario.addActionError("Erro ao colocar o item para homologa&ccedil;&atilde;o "+e.getMessage());
			logger.error("erro ao homologarItem", e);
		}
		return itemConteudo;
	}
	
	public ItemConteudo restaurarVersao(Usuario usuario, Long nuItemConteudo) throws Exception {
		ItemConteudo itemConteudo = itemConteudoDao.select(nuItemConteudo);
			if(!SecurityManager.podeAlterarItemConteudo(usuario, itemConteudo)){
				usuario.addActionError(getString("erro.autorizar.item"));
				return itemConteudo;
			}
			if(itemConteudo.getNuItemConteudoFilho()!=null && !itemConteudo.getNuItemConteudoFilho().equals(0L)){
				ItemConteudo itemConteudoFilho = itemConteudoDao.select(itemConteudo.getNuItemConteudoFilho());
				while(itemConteudoFilho!=null && itemConteudoFilho.getNuItemConteudoFilho()!=null && !itemConteudoFilho.getNuItemConteudoFilho().equals(0L)){
					//marcar como b de backup se o item a ser restaurado for publicado
					if(itemConteudo.getStSituacaoAnterior()=='p'){
						itemConteudoFilho.setStSituacaoAnterior(itemConteudoFilho.getStSituacao());
						itemConteudoFilho.setStSituacao('b');
					}
					itemConteudoDao.update(itemConteudoFilho);
					itemConteudoFilho = itemConteudoDao.select(itemConteudoFilho.getNuItemConteudoFilho());
				}
				if(itemConteudoFilho!=null){
					ItemConteudo restaurado = criarVersao(itemConteudo,usuario);					
					restaurado.setNuItemConteudoPai(itemConteudoFilho.getNuItemConteudo());
					restaurado.setNuVersao(itemConteudoFilho.getNuVersao()+1L);
					itemConteudoDao.create(restaurado);
					//atualizar o filho
					if(restaurado.getStSituacao()=='p'){
						//marca backup se o restaurado estava publicado
						itemConteudoFilho.setStSituacaoAnterior(itemConteudoFilho.getStSituacao());
						itemConteudoFilho.setStSituacao('b');
					}
					itemConteudoFilho.setNuItemConteudoFilho(restaurado.getNuItemConteudo());
					itemConteudoDao.update(itemConteudoFilho);
					itemConteudo = restaurado;
				}else{
					//addActionError("O backup n�o possui vers�o atual.");
					//Criar outra versao
					ItemConteudo restaurado = criarVersao(itemConteudo,usuario);
					//Informar o pai
					restaurado.setNuItemConteudoPai(itemConteudo.getNuItemConteudo());
					restaurado.setNuVersao(itemConteudo.getNuVersao()+1L);
					itemConteudoDao.create(restaurado);
					itemConteudo.setNuItemConteudoFilho(restaurado.getNuItemConteudo());
					itemConteudoDao.update(itemConteudo);
					itemConteudo = restaurado;
					logger.debug("Item antes sem filho restaurado. Agora possui um filho.");
				}
			}else{
				//sem filhos
				itemConteudo.setStSituacao(itemConteudo.getStSituacaoAnterior());
				itemConteudoDao.update(itemConteudo);
			}
			logDao.addLog(usuario, "Restaurou o item de conteudo ["+itemConteudo.getNoTitulo()+" id = "+itemConteudo.getNuItemConteudo()+"]");
			usuario.addActionMessage("Foi criada uma nova vers&atilde;o restaurada.");		
			return itemConteudo;
	}
	
	/**
	 * Cria uma versao do item, clona e atribui as datas
	 * @param itemConteudo
	 * @return clone do item
	 * @throws CloneNotSupportedException
	 */
	private ItemConteudo criarVersao(ItemConteudo itemConteudo,Usuario usuario) throws CloneNotSupportedException{
		ItemConteudo restaurado = (ItemConteudo) itemConteudo.clone();
		restaurado.setStSituacao(restaurado.getStSituacaoAnterior());
		restaurado.setAlteradoNuUsuario(usuario.getNuUsuario());
		restaurado.setNuUsuario(usuario.getNuUsuario());
		restaurado.setDtAlteracao(new Date());
		restaurado.setDtCriacao(new Date());
		restaurado.setNuItemConteudo(null);
		restaurado.setNuItemConteudoFilho(null);
		return restaurado;
	}
	
	public ConteudoDaoSpring getConteudoDao() {
		return conteudoDao;
	}
	
	public void setConteudoDao(ConteudoDaoSpring conteudoDao) {
		this.conteudoDao = conteudoDao;
	}
}
